#pragma once
#include <vector>
#include <fstream>
#include <Cstring>
#include "CFileRead.h"
#include "Config.h"

using std::ios;
using std::vector;

// T 一般为class或者struct  以便从二进制文件中读取数据
template <class T>
class CBinaryFileRead : public CFileRead
{

public:
    CBinaryFileRead();
    CBinaryFileRead(string path);
    ~CBinaryFileRead() override;

public:
    void Init() override;
    void Open() override;
    void Load() override;
    void loadAll() override;

public:
    CBinaryFileRead &operator>>(const T &val)       // adapt to any T type : >> overload
    {
        this->m_fileIn.read((char *)&val, sizeof(val));
        return *this;
    }

private:
    T m_t1;
    vector<T> m_v1;
};

using std::cerr;
using std::endl;

#define MALLOCSIZE 100000

template <class T>
CBinaryFileRead<T>::CBinaryFileRead()
{
    memset(&this->m_t1, 0, sizeof(this->m_t1));
    this->m_fileInPath = PATH_BIN;
    this->Init();
}

template <class T>
CBinaryFileRead<T>::CBinaryFileRead(string path)
{
    memset(&this->m_t1, 0, sizeof(this->m_t1));
    this->m_fileInPath = path;
    this->Init();
}

template <class T>
CBinaryFileRead<T>::~CBinaryFileRead()
{
    if (this->m_fileIn.is_open())
    {
        this->m_fileIn.close();
    }
}

template <class T>
void CBinaryFileRead<T>::Init()
{
    this->m_v1.reserve(MALLOCSIZE);
    // this->m_v1.resize(MALLOCSIZE);
    this->Open();
}

template <class T>
void CBinaryFileRead<T>::Open()
{
    this->m_fileIn.open(this->m_fileInPath, ios::in | ios::binary);
    if (!m_fileIn.is_open())
    {
        cerr << "File open error!" << endl;
        exit(0);
    }
}

template <class T>
void CBinaryFileRead<T>::Load()
{
    if (!this->m_fileIn.is_open() || this->m_fileIn.eof())
    {
        memset(&this->m_t1, 0, sizeof(this->m_t1));
        return;
    }
    // this->m_fileIn.read((char*)&this->m_t1, sizeof(this->m_t1));  //  the same to next line
    *this >> this->m_t1; // >> overload
}

template <class T>
void CBinaryFileRead<T>::loadAll()
{
    if (!this->m_fileIn.is_open())
    {
        return;
    }

    while (!this->m_fileIn.eof())
    {
        this->Load();
        this->m_v1.push_back(m_t1);
    }
}